<?php

namespace App\Models;

use App\Http\Library\WeChat\MiniWeChat;
use App\Services\OrderService;
use Dcat\Admin\Traits\HasDateTimeFormatter;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Throwable;

/**
 * App\Models\PaymentOrder
 *
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder newModelQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder newQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder query()
 * @mixin \Eloquent
 * @property int $id
 * @property string $out_trade_no 订单号
 * @property int $type 交易类型:0=充值订单,1=商城订单, 2=洗车订单,3=洗车卡订单
 * @property int $user_id 用户ID
 * @property int $shop_id 店铺ID
 * @property string $amount 支付金额
 * @property int $pay_status 交易状态:0=待支付,1=已支付,2=已退款
 * @property string|null $pay_at 支付时间
 * @property string|null $transaction_id 微信支付交易单号
 * @property string|null $refund_id 退款单号
 * @property string|null $refund_at 退款时间
 * @property string|null $reason 退款原因
 * @property array|null $extends 辅助信息
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder whereAmount($value)
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder whereCreatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder whereId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder whereOutTradeNo($value)
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder wherePayAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder wherePayStatus($value)
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder whereReason($value)
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder whereRefundAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder whereRefundId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder whereShopId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder whereTransactionId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder whereType($value)
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder whereUpdatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder whereUserId($value)
 * @property \Illuminate\Database\Eloquent\Collection|\App\Models\Order[] $orders
 * @property int|null $orders_count
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Order[] $services
 * @property-read int|null $services_count
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder whereExtends($value)
 * @property int $pay_way 支付方式:0=余额支付,1=微信支付
 * @method static \Illuminate\Database\Eloquent\Builder|PaymentOrder wherePayWay($value)
 */
class PaymentOrder extends Model
{
	use HasDateTimeFormatter;
    protected $table = 'payment_orders';

    protected $casts = ['extends'=>'json'];

    /**
     * 获取支付参数
     * @param $openid
     * @param $body
     * @param $out_trade_no
     * @param $amount
     * @param $notify_url
     * @return array
     */
    public static function getPayData($openid, $body, $out_trade_no, $amount, $notify_url): array
    {
        return [
            'body' => $body,
            'out_trade_no' => $out_trade_no,
            'total_fee' => $amount * 100,
            'notify_url' => $notify_url,
            'trade_type' => 'JSAPI',
            'openid' => $openid
        ];
    }

    /**
     * 支付回调
     */
    public static function notify($type = 0){
        $wechat = MiniWeChat::instance();
        $app = $wechat->getPayment();
        return $app->handlePaidNotify(function($message, $fail) use ($app,$type) {
            $out_trade_no = $message['out_trade_no'];
            $paymentOrder = self::query()->where('out_trade_no',$out_trade_no)->first();
            if(!$paymentOrder){
                return true;
            }
            if ($paymentOrder->pay_status==0){
                $result = $app->order->queryByOutTradeNumber($message['out_trade_no']);
                if($result['return_code']==='SUCCESS'&&$result['result_code']==='SUCCESS'){
                    if ($message['return_code'] === 'SUCCESS'&& $message['result_code']==='SUCCESS') {
                        $res = self::updateOrder($message,$paymentOrder, $type);
                        if(!$res['code']){
                            return $fail('支付结果出错，请稍后再通知我');
                        }
                    }else{
                        return $fail('通信失败，请稍后再通知我');
                    }
                }else{
                    return $fail('支付结果出错，请稍后再通知我');
                }
            }
            return true;
        });
    }

    /**
     * 更新交易订单
     * @param $message
     * @param PaymentOrder $payment
     * @param int $type
     * @return array
     * @throws Throwable
     */
    public static function updateOrder($message, PaymentOrder $payment, int $type = 0): array
    {
        DB::beginTransaction();
        try {
            $paymentOrder = PaymentOrder::whereId($payment->id)->lockForUpdate()->first();
            $out_trade_no = $message['out_trade_no'];
            $pay_status = 1;
            $pay_at = now()->toDateTimeLocalString();
            $paymentOrder->pay_status = $pay_status;
            $paymentOrder->pay_at = $pay_at;
            $paymentOrder->transaction_id = $message['transaction_id'];
            $user_id = $paymentOrder->user_id;
            $amount = $paymentOrder->amount;
            $extends = $paymentOrder->extends;
            $paymentOrder->save();
            if ($type==0){
                $money = floatval($amount) + floatval($extends['give_price']);
                $remark = "充值余额";
                UserMoney::money(1,$user_id,$money, $remark);
            }elseif($type==1){
                $order = GoodOrder::whereOrderNo($out_trade_no)->first();
                $order->state = 1;
                $order->pay_time = now()->format("Y-m-d H:i:s");
                $order->save();
                UserMoney::money(2,$user_id, -floatval($amount), "购买商品");
            }elseif($type==2){
                $extends = $paymentOrder->extends;
                ServiceOrder::addOrder($extends);
            }else{
                $extends = $paymentOrder->extends;
                $order_id = $paymentOrder->id;
                UserCard::addCard($order_id,$user_id,$extends);
            }
            DB::commit();
        } catch(QueryException|Throwable $e) {
            Log::error($e->getMessage());
            DB::rollback();
            return ['code'=>false,'msg'=>$e->getMessage()];
        }
        return ['code'=>true,'msg'=>'OK!'];
    }


}
